package logrus_util

import (
	"context"
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	"github.com/sirupsen/logrus"
	"io"
	"sync"
	"time"
)

var once sync.Once
var stdLogger *Logger

func Std() *Logger {
	return stdLogger
}

func InitStdLogger(debug bool) (err error) {
	stdLogger, err = New(debug)

	return
}

func New(debug bool) (logger *Logger, err error) {
	once.Do(func() {
		l := logrus.New()
		l.SetLevel(DebugLevel)
		l.SetReportCaller(true)
		l.SetFormatter(Formatter{})

		if !debug {
			l.SetLevel(ReleaseLevel)
		}

		var writer io.Writer
		writer, err = rotatelogs.New(
			DefaultFileName+".%Y%m%d%H",
			rotatelogs.WithLinkName(DefaultFileName),
			rotatelogs.WithRotationTime(time.Hour),
			rotatelogs.WithMaxAge(time.Hour*24*7),
		)

		if err != nil {
			return
		}

		hook := lfshook.NewHook(lfshook.WriterMap{
			logrus.TraceLevel: writer,
			logrus.DebugLevel: writer,
			logrus.InfoLevel:  writer,
			logrus.WarnLevel:  writer,
			logrus.ErrorLevel: writer,
			logrus.FatalLevel: writer,
			logrus.PanicLevel: writer,
		}, Formatter{})

		l.AddHook(hook)

		logger = &Logger{l}
	})

	return
}

func WithField(key string, value interface{}) *logrus.Entry {
	return stdLogger.WithField(key, value)
}

func WithFields(fields logrus.Fields) *logrus.Entry {
	return stdLogger.WithFields(fields)
}

func WithError(err error) *logrus.Entry {
	return stdLogger.WithError(err)
}

func WithContext(ctx context.Context) *logrus.Entry {
	return stdLogger.WithContext(ctx)
}

func WithTime(t time.Time) *logrus.Entry {
	return stdLogger.WithTime(t)
}

func Logf(level logrus.Level, format string, args ...interface{}) {
	stdLogger.Logf(level, format, args)
}

func Tracef(format string, args ...interface{}) {
	stdLogger.Tracef(format, args)
}

func Debugf(format string, args ...interface{}) {
	stdLogger.Debugf(format, args)
}

func Infof(format string, args ...interface{}) {
	stdLogger.Infof(format, args)
}

func Printf(format string, args ...interface{}) {
	stdLogger.Printf(format, args)
}

func Warnf(format string, args ...interface{}) {
	stdLogger.Warnf(format, args)
}

func Warningf(format string, args ...interface{}) {
	stdLogger.Warningf(format, args)
}

func Errorf(format string, args ...interface{}) {
	stdLogger.Errorf(format, args)
}

func Fatalf(format string, args ...interface{}) {
	stdLogger.Fatalf(format, args)
}

func Panicf(format string, args ...interface{}) {
	stdLogger.Panicf(format, args)
}

func Log(level logrus.Level, args ...interface{}) {
	stdLogger.Log(level, args)
}

func LogFn(level logrus.Level, fn logrus.LogFunction) {
	stdLogger.LogFn(level, fn)
}

func Trace(args ...interface{}) {
	stdLogger.Trace(args)
}

func Debug(args ...interface{}) {
	stdLogger.Debug(args)
}

func Info(args ...interface{}) {
	stdLogger.Info(args)
}

func Print(args ...interface{}) {
	stdLogger.Print(args)
}

func Warn(args ...interface{}) {
	stdLogger.Warn(args)
}

func Warning(args ...interface{}) {
	stdLogger.Warning(args)
}

func Error(args ...interface{}) {
	stdLogger.Error(args)
}

func Fatal(args ...interface{}) {
	stdLogger.Fatal(args)
}

func Panic(args ...interface{}) {
	stdLogger.Panic(args)
}

func TraceFn(fn logrus.LogFunction) {
	stdLogger.TraceFn(fn)
}

func DebugFn(fn logrus.LogFunction) {
	stdLogger.DebugFn(fn)
}

func InfoFn(fn logrus.LogFunction) {
	stdLogger.InfoFn(fn)
}

func PrintFn(fn logrus.LogFunction) {
	stdLogger.PrintFn(fn)
}

func WarnFn(fn logrus.LogFunction) {
	stdLogger.WarnFn(fn)
}

func WarningFn(fn logrus.LogFunction) {
	stdLogger.WarningFn(fn)
}

func ErrorFn(fn logrus.LogFunction) {
	stdLogger.ErrorFn(fn)
}

func FatalFn(fn logrus.LogFunction) {
	stdLogger.FatalFn(fn)
}

func PanicFn(fn logrus.LogFunction) {
	stdLogger.PanicFn(fn)
}

func Logln(level logrus.Level, args ...interface{}) {
	stdLogger.Logln(level, args)
}

func Traceln(args ...interface{}) {
	stdLogger.Traceln(args)
}

func Debugln(args ...interface{}) {
	stdLogger.Debugln(args)
}

func Infoln(args ...interface{}) {
	stdLogger.Infoln(args)
}

func Println(args ...interface{}) {
	stdLogger.Println(args)
}

func Warnln(args ...interface{}) {
	stdLogger.Warnln(args)
}

func Warningln(args ...interface{}) {
	stdLogger.Warningln(args)
}

func Errorln(args ...interface{}) {
	stdLogger.Errorln(args)
}

func Fatalln(args ...interface{}) {
	stdLogger.Fatalln(args)
}

func Panicln(args ...interface{}) {
	stdLogger.Panicln(args)
}

func Exit(code int) {
	stdLogger.Exit(code)
}
